package at.fhooe.mc.sn;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.TooManyListenersException;

/**
 * Handles the specified protocol for communication with the smart sensor.
 * @author Michael
 *
 */
public class ProtocolHandler implements SerialPortEventListener {
	private static final int TIMEOUT = 1000;
	private static final int DELAY = 10;
	
	private SerialCommunication serial;
	private String inputLine;
	private boolean isDataAvailable;

	public ProtocolHandler(SerialCommunication serial){
		inputLine = "";
		isDataAvailable = false;
		this.serial = serial;
		try {
			serial.serialPort.addEventListener(this);
		} catch (TooManyListenersException e) {
			e.printStackTrace();
		}
	}
	
	public boolean isConnected(){
		return serial.isConnected();
	}
	
	public double requestDouble(String command){
		try {
			write(command);
			waitForSerial();
			
			String reading = consume();
			
			if(reading.contains(":")){
				String[] split = reading.split(":");
				if(split[1].contains(",")){
					split = split[1].split(",");				
				}
				return Double.parseDouble(split[1]);
			} else if(!reading.isEmpty()){
				return Double.parseDouble(reading);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return 0;
	}
	
	public void requestSetDouble(String command, int param, double value){
		if(!command.endsWith(":")){
			command += "\n";
		}
		try {
			write(command+param+value);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public String request(String command){
		try {
			write(command);
			if(!command.contains("SET")){
				waitForSerial();		
				return consume();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}
	
	/**
	 * write message to smart sensor.
	 * @param message
	 * @throws IOException
	 */
	private void write(String message) throws IOException{
		if(!message.endsWith("\n")){
			message += "\n";
		}
		serial.serialPort.getOutputStream().write(message.getBytes(Charset.forName("US-ASCII")));
	}
	
	/**
	 * consume the message of the smart sensor.
	 * @return the message
	 */
	private String consume(){
		String temp = inputLine;
		inputLine = "";
		isDataAvailable = false;
		return temp;
	}
	
	/**
	 * wait until smart sensor responds or timeout is reached
	 */
	private void waitForSerial(){
		int processing = 0;
		while(!isDataAvailable&&processing<=TIMEOUT){
			try {
				Thread.sleep(DELAY);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			processing+=DELAY;
		}	
	}


	/**
	 * Handle an event on the serial port. Read the data and print it.
	 */
	public synchronized void serialEvent(SerialPortEvent oEvent) {
		if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
			try {
				inputLine = serial.getInput().readLine();
				isDataAvailable = true;
				System.out.println(inputLine);
			} catch (Exception e) {
				System.err.println(e.toString());
			}
		}
		// Ignore all the other eventTypes, but you should consider the other ones.
	}
}
